(function ($) {
    function getRows(target) {
        let state = $(target).data("datagrid");

        if (state.filterSource) {
            return state.filterSource.rows;
        } else {
            return state.data.rows;
        }
    }

    function getFooterRows(target) {
        let state = $(target).data("datagrid");

        return state.data.footer || [];
    }

    function toHtml(target, rows, footer, caption) {
        rows = rows || getRows(target);
        rows = rows.concat(footer || getFooterRows(target));

        let dg = $(target);
        // 定义表格元素的默认样式
        let trStyle = "height:32px";
        let tdDefaultStyle = "vertical-align:middle;padding:0 4px;";
        // 创建一个数组，保存表格的内容（子标签）
        let data = ["<table border='1' rull='all' style='border-collapse:collapse'>"];
        // 获取表格字段（冻结列和非冻结列）
        let fields = dg.datagrid("getColumnFields", true).concat(dg.datagrid("getColumnFields", false));

        // 设置表格头标题
        if (caption) {
            data.push("<caption>" + caption + "</caption>");
        }

        // 设置表格标题行
        data.push("<tr style='" + trStyle + "'>");

        for (let row = 0; row < fields.length; row++) {
            let col = dg.datagrid("getColumnOption", fields[row]);
            let tdStyle = tdDefaultStyle + ";width:" + col.boxWidth + "px;";

            tdStyle += ";text-align:" + (col.halign || col.align || "");

            data.push("<td style='" + tdStyle + "'>" + col.title + "</td>");
        }

        data.push("</tr>");

        // 遍历表格行数据
        $.map(rows, function (row) {
            data.push("<tr style='" + trStyle + "'>");

            for (let i = 0; i < fields.length; i ++) {
                let field = fields[i];
                let value = row[field]; // 获取字段值

                if (value == undefined) {
                    value = "";
                }

                let tdStyle = tdDefaultStyle;
                let col = dg.datagrid("getColumnOption", field);

                tdStyle += ";text-align:" + (col.align || "");

                data.push("<td style='" + tdStyle + "'>" + value + "</td>");
            }

            data.push("</tr>");
        });

        data.push("</table>");

        return data.join("");
    }

    function toArray(target, rows) {
        rows = rows || getRows(target);

        var dg = $(target);
        var fields = dg.datagrid('getColumnFields', true).concat(dg.datagrid('getColumnFields', false));
        var data = [];
        var r = [];

        for (var i = 0; i < fields.length; i++) {
            var col = dg.datagrid('getColumnOption', fields[i]);

            r.push(col.title);
        }

        data.push(r);

        $.map(rows, function (row) {
            var r = [];

            for (var i = 0; i < fields.length; i++) {
                r.push(row[fields[i]]);
            }

            data.push(r);
        });

        return data;
    }

    function print(target, param) {
        let title = null;
        let rows = null;
        let footer = null;
        let caption = null;

        if (typeof param == "string") {
            title = param;
        } else {
            title = param["title"];
            rows = param["rows"];
            footer = param["footer"];
            caption = param["caption"];
        }

        let newWindow = window.open("", "", "width=800, height=500");
        let document = newWindow.document.open();

        let data = toHtml(target, rows, footer, caption);

        let content = "";

        content += "<!doctype html>";
        content += "<html>";
        content +=     "<head>";
        content +=         "<meta charset='utf-8' />";
        content +=         "<title>" + title + "</title>";
        content +=     "</head>";
        content +=     "<body>" + data + "</body>";
        content += "</html>";

        document.write(content);
        document.close();

        newWindow.print();
    }

    function b64toBlob(data) {
        var sliceSize = 512;
        var chars = atob(data);
        var byteArrays = [];
        for (var offset = 0; offset < chars.length; offset += sliceSize) {
            var slice = chars.slice(offset, offset + sliceSize);
            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        }
        return new Blob(byteArrays, {
            type: ''
        });
    }

    function toExcel(target, param) {
        var filename = null;
        var rows = null;
        var footer = null;
        var caption = null;
        var worksheet = 'Worksheet';
        if (typeof param == 'string') {
            filename = param;
        } else {
            filename = param['filename'];
            rows = param['rows'];
            footer = param['footer'];
            caption = param['caption'];
            worksheet = param['worksheet'] || 'Worksheet';
        }
        var dg = $(target);
        var uri = 'data:application/vnd.ms-excel;base64,'
            ,
            template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>{table}</body></html>'
            , base64 = function (s) {
                return window.btoa(unescape(encodeURIComponent(s)))
            }
            , format = function (s, c) {
                return s.replace(/{(\w+)}/g, function (m, p) {
                    return c[p];
                })
            }

        var table = toHtml(target, rows, footer, caption);
        var ctx = {worksheet: worksheet, table: table};
        var data = base64(format(template, ctx));
        if (window.navigator.msSaveBlob) {
            var blob = b64toBlob(data);
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var alink = $('<a style="display:none"></a>').appendTo('body');
            alink[0].href = uri + data;
            alink[0].download = filename;
            alink[0].click();
            alink.remove();
        }
    }

    $.extend($.fn.datagrid.methods, {
        toHtml: function (jq, rows) {
            return toHtml(jq[0], rows);
        },
        toArray: function (jq, rows) {
            return toArray(jq[0], rows);
        },
        toExcel: function (jq, param) {
            return jq.each(function () {
                toExcel(this, param);
            });
        },
        print: function (jq, param) {
            return jq.each(function () {
                print(this, param);
            });
        }
    });
})(jQuery);